package yicr.untils.gis.geoHash;



import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import yicr.untils.gis.domain.NslGpsPoint;

import java.util.BitSet;
import java.util.Objects;

import static yicr.untils.gis.geoHash.NslUtilGeoHash.*;


/**
 * 非空对象一构建，则 numBits, minLatInterval,minLngInterval,longitude,latitude,geoHashString 就确定了
 * 即 对象 仅处于两种状态
 * 1. 经纬度，geoHash为空
 * 2. 经纬度，GeoHash 有效，切匹配
 */

public class  GeoHash {



    // 默认20bit,经度20个bit,纬度20个bit 对应8个字符的geohash编码，精度为：纬度方向+/-0.019km，经度方向：38m
    //只要修改 numBits,minLatInterval 和 minLngInterval 就会变化
    @Getter
    private  int numBits =20; //经纬度单独编码长度

    @Getter
    private  double minLatInterval = DefaultMinLatitudeInterval;

    @Getter
    private  double minLngInterval = DefaultMinLongitudeInterval;

    @Getter
    @Setter
    private Double longitude=null;

    @Getter
    @Setter
    private Double latitude=null;


    @Getter
    private String geoHashString=null;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        GeoHash geoHash = (GeoHash) o;
        return numBits == geoHash.numBits && Objects.equals(longitude, geoHash.longitude) && Objects.equals(latitude, geoHash.latitude) && Objects.equals(geoHashString, geoHash.geoHashString);
    }

    @Override
    public int hashCode() {
        return Objects.hash(numBits, longitude, latitude, geoHashString);
    }

    public GeoHash(){
    }

    public GeoHash(double longitude,double latitude){
        this.longitude=longitude;
        this.latitude=latitude;
        this.geoHashString=NslUtilGeoHash.encode(longitude,latitude);
    }

    public GeoHash(double longitude,double latitude,int numBits){
        this.longitude=longitude;
        this.latitude=latitude;
        setNumBits(numBits);
        this.geoHashString=NslUtilGeoHash.encode(longitude,latitude,this.numBits);
    }

    public GeoHash(String geoHashString,int numBits){
        setNumBits(numBits);
        this.geoHashString=geoHashString;
        double[] points= NslUtilGeoHash.decode(geoHashString,this.numBits);
        this.longitude=points[0];
        this.latitude=points[1];
    }

    public GeoHash(String geoHashString){
        this.geoHashString=geoHashString;
        double[] points= NslUtilGeoHash.decode(geoHashString);
        this.longitude=points[0];
        this.latitude=points[1];
    }

    public GeoHash(int numBits){
        setNumBits(numBits);
    }

    public GeoHash(int numBits, double longitude, double latitude){
        setNumBits(numBits);
        this.geoHashString=NslUtilGeoHash.encode(longitude,latitude,numBits);
        double[] points= NslUtilGeoHash.decode(geoHashString,this.numBits);
        this.longitude=points[0];
        this.latitude=points[1];
    }

    public void setNumBits(int numBits){
        if(this.numBits != numBits){
            this.numBits=numBits;
            setMinLatLngInterval();

            if(longitude !=null && latitude !=null  ){
                this.geoHashString=NslUtilGeoHash.encode(longitude,latitude,numBits);
            }

        }


    }

    private void setMinLatLngInterval() {
        minLatInterval = MAXLAT - MINLAT;
        for (int i = 0; i < numBits; i++) {
            minLatInterval /= 2.0;
        }
        minLngInterval = MAXLNG - MINLNG;
        for (int i = 0; i < numBits; i++) {
            minLngInterval /= 2.0;
        }
    }

    public void setLonLat(double longitude,double latitude){
        this.longitude=longitude;
        this.latitude=latitude;
    }

    public String getGeoHashString(){
        return NslUtilGeoHash.encode(longitude,latitude,numBits);
    }


    /**
     * 获取经度的 二进制
     * @return
     */
    public BitSet getLongitudeBit(){
        BitSet lonBits = getBits(longitude, numBits,-180, 180);
        return lonBits;
    }

    /**
     * 获取 经度 2进制 字符串表示形式
     * @return
     */
    public String getLongitudeBitString(){
        BitSet lonBits = getBits(longitude, numBits,-180, 180);
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < numBits; i++) {
            buffer.append( (lonBits.get(i))?'1':'0');
        }
        return buffer.toString();
    }

    /**
     * 获取纬度的 二进制 BitSet
     * @return
     */
    public BitSet getLatitudeBit(){
        BitSet lonBits = getBits(latitude, numBits,-90, 90);
        return lonBits;
    }

    /**
     * 获取 纬度 2进制 字符串表示形式
     * @return
     */
    public String getLatitudeBitString(){
        BitSet lonBits = getBits(latitude, numBits,-90, 90);
        StringBuilder buffer = new StringBuilder();
        for (int i = 0; i < numBits; i++) {
            buffer.append( (lonBits.get(i))?'1':'0');
        }
        return buffer.toString();
    }

    /**
     * 获取 当前点 经度 相对于 -180，-90 原点的坐标，即 00000000，X坐标
     * @return
     */
    public Long getGeoHashX(){
        long l1=Long.parseLong(getLongitudeBitString(),2);
        return l1;
    }

    /**
     * 获取 当前点 纬度 相对于 -180，-90 原点的坐标，即 00000000，Y坐标
     * @return
     */
    public Long getGeoHashY(){
        long l1=Long.parseLong(getLatitudeBitString(),2);
        return l1;
    }

    /**
     * 获取 当前点 相对于 -180,-90 原点的X/Y坐标
     * @return
     */
    public long[] getGeoHashXy(){
        long x=Long.parseLong(getLongitudeBitString(),2);
        long y=Long.parseLong(getLatitudeBitString(),2);
        long[] point=new long[2];
        point[0]=x;
        point[1]=y;
        return point;
    }

    /**
     * 返回 gpsPoint id=geoHash string
     * @return
     */
    public NslGpsPoint decode2NslGpsPoint(){
        return new NslGpsPoint(getGeoHashString(),longitude,latitude);
    }

//    public double getLongitudeInterval(){
//        double[] ceilingAndFloor=getCeilingAndFloor(0,-180,180, numBits);
//        return ceilingAndFloor[0]-ceilingAndFloor[1];
//    }
//
//    public double getLatitudeInterval(){
//        double[] ceilingAndFloor=getCeilingAndFloor(0,-90,90, numBits);
//        return ceilingAndFloor[0]-ceilingAndFloor[1];
//    }
//
//    public double getMid(double longitude,double floor, double ceiling){
//        double[] ceilingAndFloor=getCeilingAndFloor(longitude,floor,ceiling, numBits);
//        return (ceilingAndFloor[0]+ceilingAndFloor[1])/2;
//    }

    /**
     * 计算 给定 经纬度点 所在栅格的 ，中心点 经纬度
     * @param NslGpsPoint
     * @return
     */
    public NslGpsPoint getMid(NslGpsPoint NslGpsPoint){
        double[] longitudeCeilingAndFloor=getCeilingAndFloor(NslGpsPoint.getLongitude(),-180,180, numBits);
        double[] latitudeCeilingAndFloor=getCeilingAndFloor(NslGpsPoint.getLatitude(),-90,90, numBits);
        return new NslGpsPoint(null,(longitudeCeilingAndFloor[0]+longitudeCeilingAndFloor[1])/2,(latitudeCeilingAndFloor[0]+latitudeCeilingAndFloor[1])/2);
    }


public static void main(String[] args)  throws Exception{




}


    //bitSet max(index)<64
    public long getLongFromBitMap(BitSet bitSet){
        long value=0;
        long[] longArray=bitSet.toLongArray();
        value=longArray[0];
        return value;
    }


    public BitSet long2BitSet(long l){
        BitSet bitSet=new BitSet();
        for (int i = 0; i < 64; i++) {
            if((l & (1L<<i)) != 0){
                bitSet.set(i);
            }
        }

        return  bitSet;
    }


    @Override
    public String toString() {
        return "GeoHash{" +
                "numBits=" + numBits +
                ", longitude=" + longitude +
                ", latitude=" + latitude +
                ", geoHashString='" + geoHashString + '\'' +
                '}';
    }
}